//
// Created by tang on 2022/1/13.
//

#include "texture.hpp"
#include "imgui/stb_image.h"
#include "imgui/imgui_impl_opengl3_loader.h"
#include "texture_ids.hpp"
#include "utils/path_utils.hpp"

Texture::Texture(const char* path): m_texture_(malloc(sizeof (GLuint))) {
    int c;
    stbi_uc* data = stbi_load(path, &m_w_, &m_h_, &c, 4);
    if (data) {
        glGenTextures(1, (GLuint*)m_texture_);
        glBindTexture(GL_TEXTURE_2D, *(GLuint*)m_texture_);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        //        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is required on WebGL for non power-of-two textures
        //        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Same
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_w_, m_h_, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    }
    stbi_image_free(data);
}

Texture::Texture(const std::string& path) : Texture(path.data())
{
}

Texture::~Texture() {
    glDeleteTextures(1, (GLuint*)m_texture_);
    free(m_texture_);
}

ImTextureID Texture::Id() const {
    return (ImTextureID)(intptr_t)*(GLuint*)m_texture_;
}

ImVec2 Texture::Size() const {
    return { (float)m_w_, (float)m_h_ };
}

bool Texture::Valid() const
{
    return m_w_ > 0 && m_h_ > 0 && *(GLuint*)m_texture_ > 0;
}

static TexturePtr all_textures[Tex_CNT];

void TextureManager::LoadAllTexture()
{
    for (int i = 0; i < Tex_CNT; ++i)
    {
        all_textures[i].reset(new Texture(GetAssetsPath(tex_assets_names[i])));
    }
}

void TextureManager::FreeAllTexture()
{
    for (int i = 0; i < Tex_CNT; ++i)
        all_textures[i].reset();
}

TexturePtr TextureManager::Get(int id)
{
    assert (id >= 0 && id < Tex_CNT && "tex id out-of-range!!");
    return all_textures[id];
}

Texture* TextureManager::GetRaw(int id)
{
    return Get(id).get();
}

void ImGui::Image(const TexturePtr& texture, ImVec2 scale) {
    ImVec2 origin = texture->Size();
    origin.x *= scale.x;
    origin.y *= scale.y;
    ImGui::Image(texture->Id(), origin);
}

bool ImGui::ImageButton(const char* str_id, const TexturePtr& texture, ImVec2 scale) {
    ImVec2 origin = texture->Size();
    origin.x *= scale.x;
    origin.y *= scale.y;
    return ImGui::ImageButton(str_id, texture->Id(), origin);
}

void ImGui::Image(const TexturePtr& texture, float width, float height) {
    ImGui::Image(texture->Id(), ImVec2{ width, height });
}

bool ImGui::ImageButton(const char* str_id, const TexturePtr& texture, float width, float height) {
    return ImGui::ImageButton(str_id, texture->Id(), ImVec2{ width, height });
}
